<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="/Public/js/three.min.js"></script>
    <script src="/Public/js/three_shaders.js"></script>
    <script src="/Public/js/OrbitControls.js"></script>
    <script src="/Public/js/jquery-3.7.1.min.js"></script>
    <script src="/Public/js/geotiff.js"></script>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background: #1a1a2e;
            font-family: Arial, sans-serif;
        }
    </style>
</head>

<body>
<script type="module">
    const scene = new THREE.Scene();
    scene.background = new THREE.Color(0x1a1a2e);
    const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 10000);
    camera.position.set(4, 3.5, 3);
    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    const ambientLight = new THREE.AmbientLight(0x404040);
    scene.add(ambientLight);
    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
    directionalLight.position.set(1, 1, 1);
    scene.add(directionalLight);
    const controls = new THREE.OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;

    //-------------------------------------

    const file = '/Public/imgs/dem/terrain2.tif';
    const res = await fetch(file)
    const arrayBuffer = await res.arrayBuffer();
    const tiff = await GeoTIFF.fromArrayBuffer(arrayBuffer)
    const image = await tiff.getImage()
    const rasters = await image.readRasters()
    const width = image.getWidth()
    const height = image.getHeight()
    const elevationData = new Float32Array(rasters[0])
    const geometry = new THREE.PlaneGeometry(5, 5 * height / width, width - 1, height - 1)
    let maxElevation = -Infinity
    for (let i = 0; i < elevationData.length; i++) {
        if (elevationData[i] > maxElevation) {
            maxElevation = elevationData[i]
        }
    }
    let minElevation = Infinity
    for (let i = 0; i < elevationData.length; i++) {
        const num = elevationData[i]
        if (num !== 0 && num < minElevation) {
            minElevation = num
        }
    }
    const positions = geometry.attributes.position.array
    for (let i = 0; i < elevationData.length; i++) {
        if (maxElevation == minElevation) {
            positions[i * 3 + 2] = 0
        }
        else {
            positions[i * 3 + 2] = (elevationData[i] - minElevation) / (maxElevation - minElevation)
        }
    }
    geometry.attributes.position.needsUpdate = true
    geometry.computeVertexNormals()

    const base_mesh_material = new THREE.MeshBasicMaterial({
        color: '#ff0000',
        wireframe: true,
        transparent: true,
        opacity: 0.2
    })
    const base_mesh = new THREE.Mesh(geometry, base_mesh_material)
    base_mesh.rotateX(-Math.PI / 2);
    scene.add(base_mesh)

    // 存储所有找到的三角形
    let foundTriangles = []
    
    // 存储高亮网格的组
    let highlightGroup = null

    const raycaster = new THREE.Raycaster()
    const mouse = new THREE.Vector2()

    function onMouseClick(event) {
        mouse.x = (event.clientX / window.innerWidth) * 2 - 1
        mouse.y = -(event.clientY / window.innerHeight) * 2 + 1
        raycaster.setFromCamera(mouse, camera)
        const intersects = raycaster.intersectObject(base_mesh)

        if (intersects.length > 0) {
            const intersect = intersects[0]
            const face = intersect.face

            if (face) {
                // 清空之前找到的三角形
                foundTriangles = []
                
                // 移除之前的高亮显示
                if (highlightGroup) {
                    scene.remove(highlightGroup)
                    highlightGroup = null
                }

                // 递归查找所有符合条件的三角形
                findAndStoreAllTriangles(face.a, face.b, face.c)

                // 创建高亮显示的白三角形
                if (foundTriangles.length > 0) {
                    highlightFoundTriangles()
                }
                
            }
        }
    }

    // 递归查找所有符合条件的相邻三角形
    function findAndStoreAllTriangles(aIndex, bIndex, cIndex, visited = new Set()) {
        // 创建三角形唯一标识符
        const triangleKey = [aIndex, bIndex, cIndex].sort().join('-')
        
        // 如果已经访问过，跳过
        if (visited.has(triangleKey)) {
            return
        }
        
        visited.add(triangleKey)
        
        // 获取当前三角形
        const currentTriangle = getTriangle(aIndex, bIndex, cIndex)
        const currentAvgY = (currentTriangle.a.y + currentTriangle.b.y + currentTriangle.c.y) / 3
        
        // 如果是起始三角形，直接添加
        if (foundTriangles.length === 0) {
            foundTriangles.push(currentTriangle)
        }
        
        // 检查 currentAvgY 是否为 0（或接近0）
        const epsilon = 0.002 // 浮点数精度阈值
        if (Math.abs(currentAvgY) < epsilon) {
            // console.log(`当前三角形平均Y值接近0 (${currentAvgY.toFixed(6)})，终止递归查找`)
            return
        }
        
        // 1. 首先查找共享边的相邻三角形
        let bestNeighbor = null
        let bestNeighborIndices = null
        let maxDiff = 0
        
        const edgeNeighbors = findEdgeAdjacentTriangles(aIndex, bIndex, cIndex, geometry)
        
        // 在共享边的三角形中查找符合条件的
        for (const neighbor of edgeNeighbors) {
            const neighborAvgY = (neighbor.a.y + neighbor.b.y + neighbor.c.y) / 3
            const diff = currentAvgY - neighborAvgY
            
            if (diff > maxDiff) {
                maxDiff = diff
                bestNeighbor = neighbor
                bestNeighborIndices = neighbor.indices
            }
        }
        
        // 2. 如果没有找到共享边的符合条件的三角形，查找共享点的三角形
        if (!bestNeighbor) {
            const vertexNeighbors = findVertexAdjacentTriangles(aIndex, bIndex, cIndex, geometry)
            
            // 在共享点的三角形中查找符合条件的
            for (const neighbor of vertexNeighbors) {
                const neighborAvgY = (neighbor.a.y + neighbor.b.y + neighbor.c.y) / 3
                const diff = currentAvgY - neighborAvgY
                
                if (diff > maxDiff) {
                    maxDiff = diff
                    bestNeighbor = neighbor
                    bestNeighborIndices = neighbor.indices
                }
            }
        }
        
        // 如果找到符合条件的相邻三角形
        if (bestNeighbor && maxDiff > 0 && bestNeighborIndices) {
            // 添加到找到的三角形列表
            foundTriangles.push(bestNeighbor)
            console.log(currentAvgY)
            
            // 记录找到的类型
            const neighborType = bestNeighbor.indices.edgeNeighbor ? "共享边" : "共享点"
            // console.log(`找到${neighborType}的相邻三角形，Y值差值: ${maxDiff.toFixed(4)}`)
            
            // 递归查找下一个
            findAndStoreAllTriangles(
                bestNeighborIndices.a, 
                bestNeighborIndices.b, 
                bestNeighborIndices.c,
                visited
            )
        } else {
            // console.log(`未找到符合条件的相邻三角形，当前平均Y值: ${currentAvgY.toFixed(4)}`)
        }
    }

    // 查找共享边的相邻三角形
    function findEdgeAdjacentTriangles(aIndex, bIndex, cIndex, geometry) {
        const neighbors = []
        const indexArray = geometry.index ? geometry.index.array : null

        if (indexArray) {
            // 获取当前三角形的三条边
            const edges = [
                [aIndex, bIndex],
                [bIndex, cIndex],
                [cIndex, aIndex]
            ]

            // 查找所有共享边的三角形
            for (let i = 0; i < indexArray.length; i += 3) {
                const triA = indexArray[i]
                const triB = indexArray[i + 1]
                const triC = indexArray[i + 2]

                // 跳过当前三角形
                if ((triA === aIndex && triB === bIndex && triC === cIndex) ||
                    (triA === aIndex && triB === cIndex && triC === bIndex) ||
                    (triA === bIndex && triB === aIndex && triC === cIndex) ||
                    (triA === bIndex && triB === cIndex && triC === aIndex) ||
                    (triA === cIndex && triB === aIndex && triC === bIndex) ||
                    (triA === cIndex && triB === bIndex && triC === aIndex)) {
                    continue
                }

                // 检查是否共享一条边（两个顶点相同）
                for (const [edgeV1, edgeV2] of edges) {
                    const hasEdgeV1 = triA === edgeV1 || triB === edgeV1 || triC === edgeV1
                    const hasEdgeV2 = triA === edgeV2 || triB === edgeV2 || triC === edgeV2

                    if (hasEdgeV1 && hasEdgeV2) {
                        // 找到共享边的相邻三角形
                        const neighbor = getTriangle(triA, triB, triC)
                        neighbor.indices.edgeNeighbor = true // 标记为共享边
                        neighbors.push(neighbor)
                        break // 已经找到是相邻三角形，跳出内层循环
                    }
                }
            }
        }

        return neighbors
    }

    // 查找共享点的相邻三角形
    function findVertexAdjacentTriangles(aIndex, bIndex, cIndex, geometry) {
        const neighbors = []
        const indexArray = geometry.index ? geometry.index.array : null

        if (indexArray) {
            // 获取当前三角形的三个顶点索引
            const currentVertices = new Set([aIndex, bIndex, cIndex])
            
            // 查找所有共享至少一个顶点的三角形（不包括共享边的，因为那已经查过了）
            for (let i = 0; i < indexArray.length; i += 3) {
                const triA = indexArray[i]
                const triB = indexArray[i + 1]
                const triC = indexArray[i + 2]
                
                // 检查是否是当前三角形
                const isSameTriangle = 
                    (triA === aIndex && triB === bIndex && triC === cIndex) ||
                    (triA === aIndex && triB === cIndex && triC === bIndex) ||
                    (triA === bIndex && triB === aIndex && triC === cIndex) ||
                    (triA === bIndex && triB === cIndex && triC === aIndex) ||
                    (triA === cIndex && triB === aIndex && triC === bIndex) ||
                    (triA === cIndex && triB === bIndex && triC === aIndex)
                
                if (isSameTriangle) {
                    continue
                }
                
                // 检查是否共享边（如果是共享边，已经在上一步查过了，这里跳过）
                const edges = [
                    [aIndex, bIndex],
                    [bIndex, cIndex],
                    [cIndex, aIndex]
                ]
                
                let isEdgeNeighbor = false
                for (const [edgeV1, edgeV2] of edges) {
                    const hasEdgeV1 = triA === edgeV1 || triB === edgeV1 || triC === edgeV1
                    const hasEdgeV2 = triA === edgeV2 || triB === edgeV2 || triC === edgeV2
                    if (hasEdgeV1 && hasEdgeV2) {
                        isEdgeNeighbor = true
                        break
                    }
                }
                
                if (isEdgeNeighbor) {
                    continue // 跳过共享边的三角形
                }
                
                // 检查是否共享至少一个顶点
                const triangleVertices = new Set([triA, triB, triC])
                let sharedVertices = 0
                
                for (const vertex of currentVertices) {
                    if (triangleVertices.has(vertex)) {
                        sharedVertices++
                    }
                }
                
                // 如果共享至少一个顶点，则认为是相邻三角形
                if (sharedVertices > 0) {
                    // 找到共享点的相邻三角形
                    const neighbor = getTriangle(triA, triB, triC)
                    neighbor.indices.edgeNeighbor = false // 标记为共享点
                    neighbors.push(neighbor)
                }
            }
        }

        return neighbors
    }

    // 创建高亮显示找到的三角形（白色）
    function highlightFoundTriangles() {
        highlightGroup = new THREE.Group()
        
        // 为每个找到的三角形创建一个白色面片
        foundTriangles.forEach((triangle, index) => {
            // 创建几何体
            const triGeometry = new THREE.BufferGeometry()
            
            // 创建顶点数组
            const vertices = new Float32Array([
                triangle.a.x, triangle.a.y, triangle.a.z,
                triangle.b.x, triangle.b.y, triangle.b.z,
                triangle.c.x, triangle.c.y, triangle.c.z
            ])
            
            // 创建顶点缓冲区
            const positionAttribute = new THREE.BufferAttribute(vertices, 3)
            triGeometry.setAttribute('position', positionAttribute)
            
            // 设置索引
            triGeometry.setIndex([0, 1, 2])
            
            // 计算法线
            triGeometry.computeVertexNormals()
            
            // 根据是否是起始三角形设置不同颜色
            const isFirstTriangle = index === 0
            const isEdgeNeighbor = triangle.indices && triangle.indices.edgeNeighbor !== undefined
            
            let color = 0xffffff // 默认白色
            
            if (isFirstTriangle) {
                color = 0xff0000 // 起始三角形用红色
            } else if (isEdgeNeighbor && triangle.indices.edgeNeighbor) {
                color = 0x00ff00 // 共享边的三角形用绿色
            } else {
                color = 0xffff00 // 共享点的三角形用黄色
            }
            
            // 创建材质
            const material = new THREE.MeshBasicMaterial({
                color: color,
                side: THREE.DoubleSide,
                transparent: true,
                opacity: 0.7,
                depthTest: true,
                depthWrite: true
            })
            
            // 创建网格
            const mesh = new THREE.Mesh(triGeometry, material)
            highlightGroup.add(mesh)
            
            // 添加边框
            const edges = new THREE.EdgesGeometry(triGeometry)
            const lineMaterial = new THREE.LineBasicMaterial({
                color: color,
                linewidth: 1
            })
            const line = new THREE.LineSegments(edges, lineMaterial)
            highlightGroup.add(line)
        })
        
        // 添加到场景
        scene.add(highlightGroup)
    }

    // 获取三角形顶点（世界坐标）
    function getTriangle(aIndex, bIndex, cIndex) {
        const positions = geometry.attributes.position.array

        const getVertexPosition = (index) => {
            const x = positions[index * 3]
            const y = positions[index * 3 + 1]
            const z = positions[index * 3 + 2]
            const vertex = new THREE.Vector3(x, y, z)
            vertex.applyMatrix4(base_mesh.matrixWorld)
            return vertex
        }

        const triangle = {
            a: getVertexPosition(aIndex),
            b: getVertexPosition(bIndex),
            c: getVertexPosition(cIndex),
            indices: { a: aIndex, b: bIndex, c: cIndex }
        }
        
        return triangle
    }

    window.addEventListener('click', onMouseClick, false)

    //-------------------------------------

    function animate() {
        requestAnimationFrame(animate);
        renderer.render(scene, camera);
    }

    // 启动动画
    animate();

    // 窗口大小调整
    window.addEventListener('resize', () => {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    });
</script>
</body>

</html>